#ifndef _Gfx_h_
#define _Gfx_h_

#include <iostream>
using namespace std;

/** @file	Gfx.h
    @author	Julien CLEMENT
    @brief	Generic GFX engine
    @note	- Initializes SDL
		- Attempts to initialize a video mode with
		  SDL_ANYFORMAT and SDL_SWSURFACE passed by default.
		  The user can only choose between fullscreen or windowed mode.
		- Save & Restore screen system (used in special effects)
		- Various special effects like flash, screen decay and faders ...
    @note	Define USE_SDL_LAYER to have support for SDLayer_Display
    @note	Typical usage (example values):
		(...)
		Gfx * gfx;
		SDLayer_Display * ld;

		// Create a new gfx
		gfx = new Gfx;
		
		// init video mode: 32 bpp and fullscreen
		int bpp;
		bpp = gfx->init (800, 600, 32, GFX_FULLSCREEN);

		// Inform the user that the closest supported
		// depth differ from the original one
		if ( bpp != 32 ) cout << "32 bpp not supported, set to " << bpp << "\n";

		// gfx ok, init layered display
		ld = SDLayer_CreateRGBLayeredDisplay (...);
		gfx->setLayeredDisplay(ld);
		
		(... use some special effects ...)
		gfx->flash(255, 255, 255, 10, 5, 10);
		(... finish ...)
		delete gfx;
	
   @note	When releasing the Gfx object, 
		the layered display gets automatically freed
		(only when USE_SDL_LAYER is set)
   @note	A game may have a specialized Gfx class inheriting
		from "Gfx"

**/

/** We depend on SDL */
#include "SDL.h"

/** We depend on SDL_Layer */
#include "SDL_Layer.h"

/** Flags to be passed to the "init" function */
#define		GFX_FULLSCREEN		( SDL_FULLSCREEN )
#define		GFX_WINDOWED		( 0 )

class Gfx {

	public:

	static Gfx *instance() {
		if (instance_ == NULL) {
			instance_ = new Gfx;
		}
		return instance_;
	}

	static void kill() {
		if (instance_ != NULL) {
      cout << "[Killed Gfx]" << endl;
			delete instance_;
			instance_ = NULL;
		}
	}

	/** Initialization:
	  - Init SDL
	  - Init the closest video mode to the one requested.
	  @flags	GFX_WINDOWED or GFX_FULLSCREEN
	  (note that if switching to fullscreen mode fails,
	  we stay in windowed mode and report a warning)
	  @return	a positive integer with the supported depth on success
	  -1 on failure
	 */
	int init (int width, int height, int bpp, Uint32 flags);

	/** Assign a layered display */
	void setLayeredDisplay (SDLayer_Display * ld) 	{ ldisplay = ld; }

	/** Switch between windowed mode and fullscreen mode. */	    
	void toggleFullScreen (void);

	/** Save the state of the screen into a buffer */
	void saveScreen (void);

	/** Restore the state of the screen as it was when calling
	    "saveScreen" */
	void restoreScreen (void);

	/** Clear the screen by filling it in black */
	void clearScreen (void);

	/** Clear the layered display */
	void clearAll (void);

	/** Update the display */
	void update (void);

	/** Get a pointer to the layered display, needed for direct rendering */
	SDLayer_Display * getDisplay (void) { return ldisplay;      }
	SDL_Surface     * getScreen  (void) { return screen;        }
	SDL_Surface     * getBuffer  (void) { return screen_buffer; }
  SDL_Surface     * createSurface (int w, int h, bool HW = false);

	private:
	/** Default constructor */
	Gfx ();
	
	/** Destructor */
	~ Gfx ();

	/** Init functions */
	/** @return	0	on success
			-1	on failure
	*/
	int __initSDL (void);

	/** @return	a positive integer with the supported depth on success
			-1	on failure
	*/
	int __initVideoMode (int width, int height, int bpp, Uint32 flags);


	protected:
	/** The layered display (see SDL_Layer) */
	SDLayer_Display	* ldisplay;

	/** Keep a pointer to the screen surface */
	SDL_Surface * screen;
	
	/** Screen buffer for Save & Restore */
	SDL_Surface * screen_buffer;

	private:
	static Gfx * instance_;

};

#endif

